﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.ExportToRTR.CUiExportToRTRContent3DObjectDataGenerator
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using EngineeringInternalExtension;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Tecnomatix.Engineering;
using Tecnomatix.Planning;


namespace DnProcessSimulateCommands.ExportToRTR{

internal class CUiExportToRTRContent3DObjectDataGenerator
{
  private TxObjectList _objects;
  private CApExportToRTR3DData _rtr3DData;
  private CUiExportToRTRContentDataHandler _dataHandler;

  private HashSet<TxRobot> Robots { get; set; } = new HashSet<TxRobot>();

  private HashSet<ITxDevice> Devices { get; set; } = new HashSet<ITxDevice>();

  private HashSet<ITxObject> Statics { get; set; } = new HashSet<ITxObject>();

  private Dictionary<TxRobot, List<ITxDevice>> MountedTools { get; set; } = new Dictionary<TxRobot, List<ITxDevice>>();

  private Dictionary<TxRobot, List<ITxObject>> MountedObjects { get; set; } = new Dictionary<TxRobot, List<ITxObject>>();

  private Dictionary<TxRobot, Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>> AttachedDevices { get; set; } = new Dictionary<TxRobot, Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>>();

  private Dictionary<TxRobot, Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>> AttachedObjects { get; set; } = new Dictionary<TxRobot, Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>>();

  private Dictionary<string, (TxRobot, TxKinematicLink, List<TxKinematicLink>)> RobotPathToPrototypeRobot { get; set; } = new Dictionary<string, (TxRobot, TxKinematicLink, List<TxKinematicLink>)>();

  internal CUiExportToRTRContent3DObjectDataGenerator(CUiExportToRTRContentDataHandler dataHandler)
  {
    this._rtr3DData = dataHandler.RTR3DData;
    this._objects = dataHandler.SelectedObjects;
    this._dataHandler = dataHandler;
  }

  internal void Execute()
  {
    this.SortObjects();
    this.ComputeExportedObjects();
  }

  private void SortObjects()
  {
    foreach (ITxObject itxObject in (Collection<ITxObject>) this._objects)
      this.SortObject(itxObject);
    this.ExtractRobotMountedObjects();
    this.ExtractRobotAttachedObjects();
  }

  private void SortObject(ITxObject obj)
  {
    if (!CApExportToRTRUtils.IsVisibleAndHaveApprox(obj as ITxDisplayableObject))
      return;
    ITxPlanningObject itxPlanningObject;
    switch (obj)
    {
      case ITxObjectCollection collection when this.ContainsRobot(collection):
        this.SortChildren(collection);
        return;
      case TxRobot txRobot when ((Collection<ITxObject>) txRobot.DrivingJoints).Count >= 4:
        this.Robots.Add(txRobot);
        return;
      case ITxDevice itxDevice:
        this.Devices.Add(itxDevice);
        return;
      case ITxComponent _:
      case ITxGeometry _:
        this.Statics.Add(obj);
        return;
      case TxPartAppearance txPartAppearance:
        itxPlanningObject = txPartAppearance.OriginPart;
        break;
      default:
        itxPlanningObject = (ITxPlanningObject) null;
        break;
    }
    if (itxPlanningObject is TxPlanningPartInstance)
    {
      this.Statics.Add(obj);
    }
    else
    {
      if (!(obj is ITxObjectCollection))
        return;
      this.SortChildren(obj as ITxObjectCollection);
    }
  }

  private void SortChildren(ITxObjectCollection collection)
  {
    foreach (ITxObject directDescendant in (Collection<ITxObject>) collection.GetDirectDescendants((ITxTypeFilter) CApExportToRTRObjectsValidator.Filter))
      this.SortObject(directDescendant);
  }

  private bool ContainsRobot(ITxObjectCollection collection)
  {
    return ((Collection<ITxObject>) collection.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(typeof (ITxRobot)))).Count > 0;
  }

  private void ExtractRobotMountedObjects()
  {
    foreach (TxRobot robot in this.Robots)
    {
      foreach (ITxObject mountedTool in (Collection<ITxObject>) robot.MountedTools)
      {
        if (this.Statics.Contains(mountedTool))
        {
          CUiExportToRTRContent3DObjectDataGenerator.AddToRobotMapList<ITxObject>(robot, mountedTool, this.MountedObjects);
          this.Statics.Remove(mountedTool);
        }
        else if (mountedTool is ITxDevice itxDevice && this.Devices.Contains(itxDevice))
        {
          CUiExportToRTRContent3DObjectDataGenerator.AddToRobotMapList<ITxDevice>(robot, itxDevice, this.MountedTools);
          this.Devices.Remove(itxDevice);
        }
      }
    }
  }

  private static void AddToRobotMapList<T>(TxRobot robot, T obj, Dictionary<TxRobot, List<T>> map)
  {
    List<T> objList;
    if (!map.TryGetValue(robot, out objList))
    {
      objList = new List<T>();
      map.Add(robot, objList);
    }
    objList.Add(obj);
  }

  private void ExtractRobotAttachedObjects()
  {
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments1 = this.AllRobotsAttachments<ITxObject>(this.Statics);
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments2 = this.AllRobotsAttachments<ITxDevice>(this.Devices);
    foreach (TxRobot robot in this.Robots)
    {
      Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments1 = new Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>();
      Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments2 = new Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>();
      foreach (ITxObject link in (Collection<ITxObject>) robot.Links)
      {
        if (link is ITxLocatableObject parent)
        {
          this.AddAttachments(attachments1, robotAttachments1, parent);
          this.AddAttachments(attachments2, robotAttachments2, parent);
        }
      }
      foreach (ITxObject mountedTool in (Collection<ITxObject>) robot.MountedTools)
      {
        if (mountedTool is ITxLocatableObject parent)
        {
          this.AddAttachments(attachments1, robotAttachments1, parent);
          this.AddAttachments(attachments2, robotAttachments2, parent);
        }
      }
      this.AttachedObjects.Add(robot, robotAttachments1);
      this.AttachedDevices.Add(robot, robotAttachments2);
    }
  }

  private Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> AllRobotsAttachments<T>(
    HashSet<T> objects)
  {
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments = new Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>();
    foreach (T obj in objects)
    {
      if (obj is ITxLocatableObject attachableObject)
        this.AddAttachedObject(attachableObject, attachments);
    }
    return attachments;
  }

  private void AddAttachedObject(
    ITxLocatableObject attachableObject,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments)
  {
    ITxLocatableObject attachmentParent = attachableObject.AttachmentParent;
    if (attachmentParent == null || attachmentParent == TxApplication.ActiveDocument.PhysicalRoot)
      return;
    if (!attachments.ContainsKey(attachmentParent))
      attachments[attachmentParent] = new HashSet<ITxLocatableObject>();
    attachments[attachmentParent].Add(attachableObject);
  }

  private void AddAttachments(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> attachments,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments,
    ITxLocatableObject parent)
  {
    this.AddAttachment(attachments, robotAttachments, parent);
    if (!(parent is ITxObjectCollection objectCollection))
      return;
    foreach (ITxLocatableObject allDescendant in (Collection<ITxObject>) objectCollection.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(typeof (ITxLocatableObject))))
      this.AddAttachment(attachments, robotAttachments, allDescendant, parent);
  }

  private void AddAttachment(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> allAttachments,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments,
    ITxLocatableObject parent)
  {
    this.AddAttachment(allAttachments, robotAttachments, parent, parent);
  }

  private void AddAttachment(
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> allAttachments,
    Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>> robotAttachments,
    ITxLocatableObject parent,
    ITxLocatableObject key)
  {
    if (!allAttachments.ContainsKey(parent))
      return;
    foreach (ITxLocatableObject parent1 in allAttachments[parent])
    {
      if (!robotAttachments.ContainsKey(key))
        robotAttachments[key] = new HashSet<ITxLocatableObject>();
      robotAttachments[key].Add(parent1);
      if (this.Statics.Contains((ITxObject) parent1))
        this.Statics.Remove((ITxObject) parent1);
      else if (parent1 is ITxDevice itxDevice && this.Devices.Contains(itxDevice))
        this.Devices.Remove(itxDevice);
      this.AddAttachment(allAttachments, robotAttachments, parent1);
    }
  }

  private void ComputeExportedObjects()
  {
    this.HandleRobots();
    this.HandleRobotMounts();
    this.HandleRobotAttachedObjects();
    this.HandleAttachedDevices();
    this.HadnleNonRobotObjects();
  }

  private void HandleRobots()
  {
    foreach (TxRobot robot in this.Robots)
      this.HandleSingleRobot(robot);
  }

  private void HandleSingleRobot(TxRobot robot)
  {
    this.HandleRobotPrototype(robot);
    this.HandleInstanceLinks(robot);
    this.HandleRobotSubDevices(robot);
  }

  private void HandleRobotPrototype(TxRobot robot)
  {
    string componentPath = TxComponentEx.GetComponentPath((ITxComponent) robot, false);
    if (this.RobotPathToPrototypeRobot.TryGetValue(componentPath, out (TxRobot, TxKinematicLink, List<TxKinematicLink>) _))
      return;
    TxKinematicLink baseLink = this.GetBaseLink(robot);
    (TxRobot, TxKinematicLink, List<TxKinematicLink>) valueTuple = (robot, baseLink, new List<TxKinematicLink>());
    foreach (ITxObject drivingJoint in (Collection<ITxObject>) robot.DrivingJoints)
    {
      TxJoint txJoint = drivingJoint as TxJoint;
      if (TxJoint.op_Inequality(txJoint, (ITxObject) null))
      {
        TxKinematicLink childLink = txJoint.ChildLink;
        valueTuple.Item3.Add(childLink);
      }
    }
    this.RobotPathToPrototypeRobot.Add(componentPath, valueTuple);
    this._rtr3DData.RobotProrotypeData.Add(robot, new CApExportToRTR3DData.RobotPrototTypeExport3DData()
    {
      BaseLink = baseLink,
      Links = valueTuple.Item3
    });
  }

  private void HandleRobotSubDevices(TxRobot robot)
  {
    foreach (ITxObject allDescendant in (Collection<ITxObject>) robot.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(typeof (ITxDevice))))
    {
      if (CApExportToRTRUtils.IsVisible(allDescendant as ITxDisplayableObject))
        this._rtr3DData.ToBlankNotExportedSubDevices.Add(allDescendant, robot);
    }
  }

  private void HandleInstanceLinks(TxRobot robot)
  {
    TxKinematicLink baseLink = this.GetBaseLink(robot);
    List<ITxObject> exportObjects = new List<ITxObject>();
    if (TxKinematicLink.op_Inequality(baseLink, (ITxObject) null))
    {
      this.AddToRobotObjectsToExport(robot, (ITxObject) baseLink);
      this.AddToObjectsToExport((ITxObject) baseLink, exportObjects);
    }
    foreach (ITxObject drivingJoint in (Collection<ITxObject>) robot.DrivingJoints)
    {
      TxJoint txJoint = drivingJoint as TxJoint;
      if (TxJoint.op_Inequality(txJoint, (ITxObject) null))
      {
        TxKinematicLink childLink = txJoint.ChildLink;
        this.AddToRobotObjectsToExport(robot, (ITxObject) childLink);
        this.AddToObjectsToExport((ITxObject) childLink, exportObjects);
      }
    }
  }

  private TxKinematicLink GetBaseLink(TxRobot robot)
  {
    List<TxKinematicLink> robotLinks = new List<TxKinematicLink>();
    ((IEnumerable<ITxObject>) robot.DrivingJoints).ToList<ITxObject>().ForEach((Action<ITxObject>) (x => robotLinks.Add((x as TxJoint).ParentLink)));
    foreach (TxKinematicLink baseLink in robotLinks)
    {
      if (TxJoint.op_Equality(baseLink.ParentJoint, (ITxObject) null))
        return baseLink;
    }
    return (TxKinematicLink) null;
  }

  private void HadnleNonRobotObjects()
  {
    this.HandleStaticObjects<ITxObject>(this.Statics);
    this.HandleStaticObjects<ITxDevice>(this.Devices);
  }

  private void HandleStaticObjects<T>(HashSet<T> objectSet)
  {
    List<ITxObject> exportObjects = new List<ITxObject>();
    foreach (T obj in objectSet)
      this.AddToObjectsToExport((ITxObject) (object) obj, exportObjects);
  }

  private void HandleAttachedDevices()
  {
    foreach (KeyValuePair<TxRobot, Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>> attachedDevice in this.AttachedDevices)
    {
      TxObjectList<ITxDevice> coupledFupa = TxRobotEx.GetCoupledFupa((ITxRobot) attachedDevice.Key);
      foreach (KeyValuePair<ITxLocatableObject, HashSet<ITxLocatableObject>> keyValuePair in attachedDevice.Value)
      {
        foreach (ITxDisplayableObject key in keyValuePair.Value)
        {
          if (!(key is ITxTool) && ((Collection<ITxDevice>) coupledFupa).Contains(key as ITxDevice))
            this._rtr3DData.ToBlankNotExportedAttachedTools.Add((ITxObject) key, attachedDevice.Key);
        }
      }
    }
  }

  private void HandleRobotMounts()
  {
    foreach (KeyValuePair<TxRobot, List<ITxDevice>> mountedTool in this.MountedTools)
      this.HanldeMountedDevices(mountedTool.Key, mountedTool.Value);
    foreach (KeyValuePair<TxRobot, List<ITxObject>> mountedObject in this.MountedObjects)
      this.HandleMountedObjects(mountedObject.Key, mountedObject.Value);
  }

  private void HanldeMountedDevices(TxRobot robot, List<ITxDevice> mountedDevices)
  {
    List<ITxDevice> itxDeviceList = new List<ITxDevice>();
    foreach (ITxDevice mountedDevice in mountedDevices)
    {
      if (this.IsToolExternalAxis(mountedDevice, robot))
      {
        List<ITxObject> exportObjects = new List<ITxObject>();
        foreach (TxJoint txJoint in (Collection<ITxObject>) mountedDevice.AllJointsAfterCompilation)
        {
          TxKinematicLink childLink = txJoint.ChildLink;
          exportObjects.Add((ITxObject) childLink);
        }
        this.AddToRobotObjectsToExport(robot, (ITxObject) mountedDevice);
        this.AddToObjectsToExportAsKinematics((ITxObject) mountedDevice, exportObjects);
      }
      else
      {
        CUiExportToRTRContent3DObjectDataGenerator.AddToRobotMapList<ITxObject>(robot, (ITxObject) mountedDevice, this.MountedObjects);
        itxDeviceList.Add(mountedDevice);
      }
    }
    foreach (ITxDevice itxDevice in itxDeviceList)
      mountedDevices.Remove(itxDevice);
  }

  private void HandleMountedObjects(TxRobot robot, List<ITxObject> mountedObjects)
  {
    List<ITxObject> exportObjects = new List<ITxObject>();
    foreach (ITxObject mountedObject in mountedObjects)
    {
      this.AddToRobotObjectsToExport(robot, mountedObject);
      this.AddToObjectsToExport(mountedObject, exportObjects);
    }
  }

  private void HandleRobotAttachedObjects()
  {
    List<ITxObject> emptyList = new List<ITxObject>();
    foreach (KeyValuePair<TxRobot, Dictionary<ITxLocatableObject, HashSet<ITxLocatableObject>>> attachedObject in this.AttachedObjects)
    {
      TxRobot key = attachedObject.Key;
      foreach (KeyValuePair<ITxLocatableObject, HashSet<ITxLocatableObject>> keyValuePair in attachedObject.Value)
      {
        if (!this._rtr3DData.ToBlankNotExportedAttachedTools.ContainsKey((ITxObject) keyValuePair.Key))
        {
          List<ITxObject> list = ((IEnumerable<ITxObject>) keyValuePair.Value).ToList<ITxObject>();
          this.AddToObjectsToExport((ITxObject) keyValuePair.Key, list);
          list.ForEach((Action<ITxObject>) (obj => this.AddToObjectsToExport(obj, emptyList)));
        }
      }
    }
  }

  private void AddToRobotObjectsToExport(TxRobot robot, ITxObject obj)
  {
    List<ITxObject> itxObjectList;
    if (!this._rtr3DData.RobotObjectsToExport.TryGetValue(robot, out itxObjectList))
    {
      itxObjectList = new List<ITxObject>();
      this._rtr3DData.RobotObjectsToExport.Add(robot, itxObjectList);
    }
    itxObjectList.Add(obj);
  }

  private void AddToObjectsToExportAsKinematics(ITxObject obj, List<ITxObject> exportObjects)
  {
    this.AddToObjectsToExport(obj, exportObjects, true);
  }

  private void AddToObjectsToExport(ITxObject obj, List<ITxObject> exportObjects, bool isKiematic = false)
  {
    CApExportToRTR3DData.ObjectExport3DData objectExport3Ddata;
    if (!this._rtr3DData.ObjectWithSubObjectToExport.TryGetValue(obj, out objectExport3Ddata))
    {
      objectExport3Ddata = new CApExportToRTR3DData.ObjectExport3DData();
      this._rtr3DData.ObjectWithSubObjectToExport.Add(obj, objectExport3Ddata);
    }
    foreach (ITxObject exportObject in exportObjects)
      objectExport3Ddata.SeparateFromParent3D.Add(exportObject);
    objectExport3Ddata.IsWithKinematics = isKiematic;
  }

  private bool IsToolExternalAxis(ITxDevice device, TxRobot robot)
  {
    bool flag = false;
    CApExportToRTRRobotToolData rtrRobotToolData;
    CApExportToRTRRobotData exportToRtrRobotData;
    if (this._dataHandler.DataOfTools.TryGetValue(device, out rtrRobotToolData) && this._dataHandler.DataOfRobots.TryGetValue((ITxRobot) robot, out exportToRtrRobotData))
      flag = rtrRobotToolData.IsServoGun && rtrRobotToolData.IsExternalAxis && !rtrRobotToolData.IsGunWithLoops && rtrRobotToolData.IsGunWithAvailableKinematicFunctions && !exportToRtrRobotData.HasUnSupportedExternalAxes;
    return flag;
  }
}
